package com.mgface.eth.api;

import com.mgface.eth.tool.TxHashGetReceipt;
import com.mgface.eth.tool.Web3JInstance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.response.EthGetCode;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.utils.Numeric;

import java.math.BigInteger;
import java.util.Collections;

/**
 * @author wanyuxiang
 * @version 1.0
 * @project eth
 * @desc 部署智能合约
 * @create 2018-06-27 16:37
 **/
public class CreateContract {

	private static final Logger log = LoggerFactory.getLogger(CreateContract.class);

	static final BigInteger GAS_PRICE = BigInteger.valueOf(22_000_000_000L);
	static final BigInteger GAS_LIMIT = BigInteger.valueOf(4_300_000);

	/**
	 * @param contractData 智能合约的创建代码（16进制）
	 * @throws Exception <p>
	 *                   pragma solidity ^0.4.0;
	 *                   <p>
	 *                   contract Data{
	 *                   <p>
	 *                   uint256 public data;
	 *                   <p>
	 *                   constructor(uint256 initdata) public {
	 *                   data = initdata;
	 *                   }
	 *                   function setData(uint256 _data) public payable{
	 *                   data += _data;
	 *                   }
	 *                   <p>
	 *                   function getData() public constant returns (uint256) {
	 *                   return data;
	 *                   }
	 *                   }
	 */
	public static void createSmartContract(String contractData, boolean existConstructor, String encodedConstructor, boolean existTranferEth, BigInteger ethValue) throws Exception {
		//假如存在构造器

		RawTransaction rawTransaction = RawTransaction.createContractTransaction(
				GetNonce.getNonce("0x70982B82D6EdFDC91B0998c62954e703B7407747"), GAS_PRICE, GAS_LIMIT, existTranferEth ? ethValue : BigInteger.ZERO, existConstructor ? contractData + encodedConstructor : contractData);
		Credentials credentials = Credentials.create("8341e5451480e81f220610f9ada693fe7a5dcc19d28833ce0c2f4f4d7f649104");
		byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
		String hexValue = Numeric.toHexString(signedMessage);
		EthSendTransaction ethSendTransaction = Web3JInstance.getWeb3jInstance().ethSendRawTransaction(hexValue).sendAsync().get();

		String transactionHash = ethSendTransaction.getTransactionHash();
		log.info("获取到交易hash值:{}", transactionHash);
		TransactionReceipt transactionReceipt = TxHashGetReceipt.passTxHashGetReceipt(transactionHash);
		log.info("获取到合约的地址:{}", transactionReceipt.getContractAddress());
		//验证已部署的智能合约是否可用
		EthGetCode ethGetCode = Web3JInstance.getWeb3jInstance()
				.ethGetCode(transactionReceipt.getContractAddress(), DefaultBlockParameterName.LATEST)
				.send();
		if (!ethGetCode.hasError()) {
			String code = Numeric.cleanHexPrefix(ethGetCode.getCode());
			// There may be multiple contracts in the Solidity bytecode, hence we only check for a
			// match with a subset
			log.info("合约是否可用:{}",!code.isEmpty() && contractData.contains(code));
		}

	}


	public static void main(String[] args) throws Exception {

		String encodedConstructor = FunctionEncoder.encodeConstructor(Collections.singletonList(new Uint256(100)));
		createSmartContract("0x60806040526040516020806101508339810180604052810190808051906020019092919050505080600081905550506101138061003d6000396000f3006080604052600436106053576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bc5de301460585780635b4b73a914608057806373d4a13a14609e575b600080fd5b348015606357600080fd5b50606a60c6565b6040518082815260200191505060405180910390f35b609c6004803603810190808035906020019092919050505060cf565b005b34801560a957600080fd5b5060b060e1565b6040518082815260200191505060405180910390f35b60008054905090565b80600080828254019250508190555050565b600054815600a165627a7a7230582035a255212c88d5119336736c38c4569886edaa29ad26871e44ad9153fcc4e3a80029",
				true, encodedConstructor, true, BigInteger.valueOf(10L));
	}
}
